package com.chyb.cloud;


import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URI;

/*注入到Spring容器中，之后会将所有注入到容器中的过滤器进行合并，形成过滤器列表*/
//@Component
@Slf4j
/*这里是自定配置全局过滤器，就是每一个路由都会去执行的*/
public class MyGlobalFilter implements GlobalFilter, Ordered {
    public static final String BEGIN_VISIT_TIME = "BEGIN_VISIT_TIME";/*初始化方法执行的开始时间*/

    /**
     *用来接受响应请求报文，以及控制放行操作（这里有点像将拦截器中的preHandle[访问前拦截方法]和postHandle[访问后拦截方法]结合到一起了）
     * @param exchange :类似于Server，它里面封装了三个属性：
     *                 ServerHttpResponse、ServerHttpRequest：这两个属性存储着：请求/响应的报文，所以可以通过exchange这个参数获取到这些属性
     *                 Map<String, Object>：这属性就是我们要进行额外的添加对象就可以添加到这里，运用的方法就直接.pus即可
     * @param chain : 这个属性可以控制过滤器的放行操作
     * @return 这里返回的类型是Mono这个类型是在SpringBoot响应式编程中所引出的类，适用于高并发和高吞吐量场景（在资源有限的情况下提高系统的吞吐量和伸缩性【并非提高性能】）
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("=====" + exchange.getAttributes().get(BEGIN_VISIT_TIME) + "=====");
        exchange.getAttributes().put(BEGIN_VISIT_TIME, System.currentTimeMillis());
        System.out.println("------" + exchange.getAttributes().get(BEGIN_VISIT_TIME) + "-----");

        /**
         * 这里的chain.filter(exchange)是放行操作，而.then()是任务串联(在 Mono完成后触发新任务，但不依赖前一个任务的输出结果。)
         */
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            Long beginTime = exchange.getAttribute(BEGIN_VISIT_TIME);
            URI uri = exchange.getRequest().getURI();
            if (beginTime != null) {
                log.info("访问接口主机：{}", uri.getHost());
                log.info("访问接口端口号：{}", uri.getPort());
                log.info("放文件接口URL：{}", uri.getPath());
                log.info("访问接口的URL参数：{}", uri.getQuery());
                log.info("访问时长：{}ms", (System.currentTimeMillis() - beginTime));
                log.info("============================================");
                System.out.println();
            }
        }));
    }

    /**
     * 设置执行接口进行排序，返回值越小越靠前
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}
